package yasuo;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;

/**
 * 功能：压缩文件成zip格式  
 */
public class ZipUtils {
	private static int BUFFER = 1024 * 4; // 缓冲大小
	private static byte[] B_ARRAY = new byte[BUFFER];

	/**
	 * 生成zip文件
	 * @param inputFileName 要打包的文件夹或文件的路径(严重警告：inputFileName不能是targetFileName的祖先路径)
	 * @param targetFileName 打包后的文件路径
	 * @param base 压缩文件的路径
	 * @return
	 */
	public static File createZip(String inputFileName, String targetFileName, String base) {
		File inputFile = new File(inputFileName);
		if(!inputFile.exists())
			return null;
		ZipOutputStream out = getZipOutputStream(targetFileName);
		File targetFile = new File(targetFileName);
		
		compress(out, inputFile, base, targetFile);
		try {
			if (null != out) {
				out.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return targetFile;
	}

	/**
	 * 生成zip文件
	 * @param inputFileName 要打包的文件夹或文件的路径的列表(严重警告：inputFileNameList中的路径不能有targetFileName的祖先路径)
	 * @param targetFileName 打包后的文件路径
	 * @param base 压缩文件的路径
	 * @return
	 */
	public static File createZip(List<String> inputFileNameList, String targetFileName, String base) {
		ZipOutputStream out = getZipOutputStream(targetFileName);
		File targetFile = new File(targetFileName);
		
		for (String inputFileName : inputFileNameList) {
			File inputFile = new File(inputFileName);
			compress(out, inputFile, base, targetFile);
		}

		try {
			if (null != out) {
				out.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return targetFile;
	}

	private static void compress(ZipOutputStream out, File inputFile, String base, File targetFile) {
		if (inputFile.isDirectory()) // 打包文件夹
		{
			packFolder(out, inputFile, base, targetFile);
		} else // 打包文件
		{
			packFile(out, inputFile, base);
		}
	}

	private static void packFolder(ZipOutputStream out, File inputFile, String base, final File targetFile) {
		File[] fileList = inputFile.listFiles(new FileFilter() {
			@Override
			public boolean accept(File file) {
				return !file.equals(targetFile);
			}
		});
		base = base.length() == 0 ? "" : base + "/";
		try {
			// 在打包文件中添加路径
			if(!"".equals(base)){
				out.putNextEntry(new ZipEntry(base));
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		for (File file : fileList) {
			compress(out, file, base + file.getName(), null);
		}
	}

	private static void packFile(ZipOutputStream out, File inputFile, String base) {
		ZipEntry entry = new ZipEntry(base);

		// 设置打包文件的大小，如果不设置，打包有内容的文件时，会报错
		//entry.setSize(inputFile.length());
		try {
			out.putNextEntry(entry);
		} catch (IOException e) {
			e.printStackTrace();
		}
		FileInputStream in = null;
		try {
			in = new FileInputStream(inputFile);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		int b = 0;

		try {
			while ((b = in.read(B_ARRAY, 0, BUFFER)) != -1) {
				out.write(B_ARRAY, 0, b);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (NullPointerException e) {
			System.err
					.println("NullPointerException info ======= [FileInputStream is null]");
		} finally {
			try {
				if (null != in) {
					in.close();
				}
				if (null != out) {
					out.closeEntry();
				}
			} catch (IOException e) {

			}
		}
	}

	private static ZipOutputStream getZipOutputStream(String targetFileName) {
		// 如果打包文件没有.tar后缀名，就自动加上
		targetFileName = targetFileName.endsWith(".zip") ? targetFileName
				: targetFileName + ".zip";
		FileOutputStream fileOutputStream = null;
		try {
			fileOutputStream = new FileOutputStream(targetFileName);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
				fileOutputStream);
		
		ZipOutputStream out = new ZipOutputStream(bufferedOutputStream);

		return out;
	}
	
	public static void main(String[] args) {
		createZip("E:/var", "E:/var/test5.zip","");
	}

}